﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Globalization;

namespace ResourceBlender_Express {
    /// <summary>
    /// A window to display duplicate resources.
    /// </summary>
    public partial class WinDuplicateResources : Window {
        private ObservableSortedDictionary<string, CultureInfo> languages;

        private DataTemplate ascSorted,
                             descSorted;

        /// <summary>
        /// Initializes a new <see cref="WinDuplicateResources"/> and shows all languages.
        /// </summary>
        public WinDuplicateResources() :
            this(new ObservableSortedDictionary<string, CultureInfo>(new Comparers.CultureInfoEnglshNameComparer(), new Comparers.StringEqualityComparer())) { }

        /// <summary>
        /// Initializes a new <see cref="WinDuplicateResources"/> to display the specified languages.
        /// </summary>
        /// <param name="languages">The languages to show as RadioButtons for which duplicates can be shown.</param>
        public WinDuplicateResources(ObservableSortedDictionary<string, CultureInfo> langs) {
            InitializeComponent();
            ascSorted = (DataTemplate)FindResource("HeaderTemplateAsc");
            descSorted = (DataTemplate)FindResource("HeaderTemplateDesc");
            this.languages = langs;
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (s, dwe) => {
                if(languages.Count == 0) {
                    Database db = null;
                    try {
                        if(db == null || !db.Connected) {
                            db = new Database();
                            db.OpenConnection();
                        }
                        using(Database.Command cmd = db.CreateCommand()) {
                            cmd.CommandText = string.Format(@"SELECT DISTINCT language FROM {0}resources", db.TablePrefix);
                            DbDataReader reader = cmd.ExecuteReader();
                            while(reader.Read()) {
                                CultureInfo info = Utils.GetCultureInfo(reader[0].ToString());
                                if(info != null) {
                                    languages.Add(info.Name, info);
                                }
                            }
                        }
                    } catch(Exception ex) {
                        dwe.Result = ex.Message;
                    } finally {
                        if(db != null && db.Connected) {
                            try {
                                db.CloseConnection();
                            } catch { }
                        }
                    }
                }
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                SetStatus(null, false);
                lstDuplicates.IsEnabled = true;
                lstLanguages.ItemsSource = languages;
                if(languages.Count > 0) {
                    lstLanguages.SelectedIndex = 0;
                    if(rwe.Result == null) {
                        NavigationCommands.Refresh.Execute(null, null);
                    } else {
                        DialogBox.ShowAlert(this, "Could not connect to database - " + rwe.Result.ToString(), "Database Error");
                    }
                } else {
                    DialogBox.ShowAlert(this, "No resources have been added", "Database Error");
                    Close();
                }
            };
            SetStatus("Loading available languages...", true);
            lstDuplicates.IsEnabled = false;
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Determines whether the RefreshResources command can be executed
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExecuteRefreshResources(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = this.IsLoaded && lstLanguages.SelectedValue != null;
        }

        /// <summary>
        /// Shows duplicate resources for the selected language.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void RefreshResources(object sender, RoutedEventArgs e) {
            if(lstLanguages.SelectedValue == null) {
                return;
            }
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (s, dwe) => {
                Database db = null;
                try {
                    if(db == null || !db.Connected) {
                        db = new Database();
                        db.OpenConnection();
                    }
                    using(Database.Command cmd = db.CreateCommand()) {
                        switch(db.InstanceType) {
                            case Database.DatabaseType.MySQL:
                            case Database.DatabaseType.SQLite:
                                cmd.CommandText = string.Format(@"SELECT r.resourceid, r.translation, COUNT(*) AS number FROM {0}resources AS r WHERE language = @lang GROUP BY translation HAVING COUNT(*) > 1 ORDER BY translation", db.TablePrefix);
                                break;
                            case Database.DatabaseType.SQLServer:
                                cmd.CommandText = string.Format(@"SELECT translation,resourceid,number FROM
                                                (SELECT ROW_NUMBER() OVER (PARTITION BY translation ORDER BY resourceid DESC) 
                                                AS Seq,translation,resourceid,
                                                COUNT(resourceid) OVER (PARTITION BY translation) AS number
                                                FROM {0}resources
                                                WHERE language = @lang
                                                )t WHERE Seq=1 AND number > 1", db.TablePrefix);
                                break;
                        }
                        cmd.AddParameterWithValue("@lang", dwe.Argument);
                        DataTable dt = new DataTable();
                        Database.DataAdapter adapter = new Database.DataAdapter(cmd);
                        adapter.Fill(dt);
                        dwe.Result = dt;
                    }
                } catch(Exception ex) {
                    dwe.Result = ex.Message;
                } finally {
                    if(db != null && db.Connected) {
                        try {
                            db.CloseConnection();
                        } catch { }
                    }
                }
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                SetStatus(null, false);
                lstDuplicates.IsEnabled = true;
                DataTable dt = rwe.Result as DataTable;
                if(dt != null) {
                    int numDuplicates = dt.DefaultView.Count;
                    SetStatus(string.Format("{0} duplicate {1} for {2}", numDuplicates, numDuplicates == 1 ? "resource" : "resources", ((KeyValuePair<string, CultureInfo>)lstLanguages.SelectedItem).Value.EnglishName), false);
                    lstDuplicates.DataContext = dt;
                } else {
                    DialogBox.ShowAlert(this, "Error: Could not connect to database - " + rwe.Result.ToString(), "Database Error");
                }
            };
            SetStatus("Loading duplicate resources...", true);
            lstDuplicates.IsEnabled = false;
            worker.RunWorkerAsync(lstLanguages.SelectedValue);
        }

        /// <summary>
        /// Determines whether the ShowDuplicateDetails command can be executed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExecuteShowDuplicateDetails(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = this.IsLoaded && lstLanguages.SelectedIndex >= 0 && lstDuplicates.SelectedIndex >= 0;
        }

        /// <summary>
        /// Opens a window to show details for an duplicate resource.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowDuplicateDetails(object sender, ExecutedRoutedEventArgs e) {
            if(lstLanguages.SelectedIndex < 0 || lstDuplicates.SelectedIndex < 0) {
                return;
            }
            WinDuplicateDetails dlg = new WinDuplicateDetails(languages, lstLanguages.SelectedValue.ToString(), lstDuplicates.SelectedValue.ToString());
            dlg.Owner = this;
            dlg.ShowDialog();
            NavigationCommands.Refresh.Execute(null, null);
        }

        /// <summary>
        /// Sorts the grid.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void OnColumnHeaderClick(object sender, RoutedEventArgs e) {
            if(e.OriginalSource is GridViewColumnHeader) { // sort the grid
                GridViewColumn column = ((GridViewColumnHeader)e.OriginalSource).Column;
                string sortPath = column.DisplayMemberBinding == null ? (column.CellTemplate.DataType ?? string.Empty).ToString() : (column.DisplayMemberBinding as Binding).Path.Path;
                if(sortPath.Length == 0) {
                    return; // no field specified
                }
                if(column.HeaderTemplate == ascSorted) {
                    column.HeaderTemplate = null;
                    (lstDuplicates.DataContext as DataTable).DefaultView.Sort = sortPath + " DESC"; ;
                } else if(column.HeaderTemplate == descSorted) {
                    column.HeaderTemplate = ascSorted;
                    (lstDuplicates.DataContext as DataTable).DefaultView.Sort = "";
                } else {
                    column.HeaderTemplate = ascSorted;
                    (lstDuplicates.DataContext as DataTable).DefaultView.Sort = sortPath + " ASC";
                }
            }
        }

        /// <summary>
        /// Sets the text on the status message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="showProgress"><c>true</c> if the progress bar should be shown, otherwise <c>false</c>.</param>
        private void SetStatus(string message, bool showProgress) {
            prgStatus.Visibility = showProgress ? Visibility.Visible : Visibility.Hidden;
            if(message == null) {
                lblStatus.Visibility = Visibility.Hidden;
            } else {
                lblStatus.Visibility = Visibility.Visible;
                lblStatus.Content = message;
            }
        }

        /// <summary>
        /// Shows the help file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowHelp(object sender, ExecutedRoutedEventArgs e) {
            Utils.OpenHelp("Unused.Resources.html");
        }
    }
}
